#include "serialization.h"
#include <QtCore/QDataStream>
#include <memory>
#include <QtCore/QDebug>

namespace acidone
{

void saveDatabase(QDataStream& out, Database* database)
{
	// database version
	out << int(2);


	// save categories
	QMap<Category*, int> c2i;
	{
		Database::Categories categories = database->categories();
		QStringList names;

		for(int i = 0; i < categories.count(); ++i)
		{
			c2i.insert(categories.at(i), i);
			names.append(categories.at(i)->name());
		}

		out << names;
	}

	// save subjects
	QMap<Subject*, int> s2i;
	{
		Database::Subjects subjects = database->subjects();
		QStringList names;

		for(int i = 0; i < subjects.count(); ++i)
		{
			s2i.insert(subjects.at(i), i);
			names.append(subjects.at(i)->name());
		}

		out << names;
	}

	// save tasks
	{
		// number of tasks
		Database::TaskList tasks = database->tasks();
		out << tasks.count();

		foreach(Task* task, tasks)
		{
			Database::Categories categories = task->categories();
			{
				QList<int> numbers;
				foreach(Category* category, categories)
					numbers.append(c2i[category]);
				out << numbers;
			}
			out << task->caption();
			out << task->beginDateTime();
			out << task->endDateTime();
			out << int(task->priority());
			out << task->notes();
			out << s2i[task->subject()];
			out << task->creationDateTime();
			out << task->completionDateTime();
		}
	}
}

void saveDatabase(QIODevice* device, Database* database)
{
	QDataStream out(device);
	saveDatabase(out, database);
}

Database* loadDatabase(QDataStream& in)
{
	// version
	int version = 0;
	in >> version;

	if (version != 1 && version != 2)
	{
		qDebug() << "invalid database version";
		return 0;
	}

	std::auto_ptr<Database> database(new Database);

	// read categories
	QMap<int, Category*> i2c;
	{
		QStringList names;
		in >> names;
		for(int i = 0; i < names.count(); ++i)
		{
			i2c.insert(i, database->addCategory(names[i]));
		}
	}

	// read subjects
	QMap<int, Subject*> i2s;
	{
		QStringList names;
		in >> names;
		for(int i = 0; i < names.count(); ++i)
		{
			i2s.insert(i, database->addSubject(names[i]));
		}
	}
	// read tasks
	{
		int taskCount = 0;
		in >> taskCount;

		for(int i = 0; i < taskCount; ++i)
		{
			QList<int> categories;
			QString caption, notes;
			QDateTime beginDateTime, endDateTime, creationDateTime, completionDateTime;
			int priority, subject;

			in >> categories >> caption >> beginDateTime >> endDateTime >> priority
					>>  notes >> subject;

			if (version > 1)
			{
				in >> creationDateTime >> completionDateTime;
			}

			Task* task = new Task;
			for(int i = 0; i < categories.count(); ++i)
				task->addCategory(i2c[categories[i]]);
			task->setCaption(caption);
			task->setBeginDateTime(beginDateTime);
			task->setEndDateTime(endDateTime);
			task->setPriority(Task::Priority(priority));
			task->setNotes(notes);
			task->setSubject(i2s[subject]);
			task->setCreationDateTime(creationDateTime);
			task->setCompletionDateTime(completionDateTime);

			database->addTask(task);
		}
	}

	return database.release();
}

Database* loadDatabase(QIODevice* device)
{
	QDataStream in(device);
	return loadDatabase(in);
}

}
